{{!

  Copyright (c) Meta Platforms, Inc. and affiliates.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

}}{{!
Generated Python classes for Thrift types
}}
{{> common/auto_generated_py}}

{{^program:generate_immutable_types}}
{{^program:generate_mutable_types}}
import builtins

{{/program:generate_mutable_types}}
{{/program:generate_immutable_types}}
import folly.iobuf as _fbthrift_iobuf

{{#program:enable_abstract_types?}}
from abc import ABCMeta as _fbthrift_ABCMeta
import {{program:module_path}}.thrift_abstract_types as _fbthrift_abstract_types
{{/program:enable_abstract_types?}}
{{#program:has_streaming_types?}}
from thrift.python.protocol import RpcKind as _fbthrift__RpcKind
{{/program:has_streaming_types?}}
{{#program:has_sink_functions?}}
{{> types/sink_imports }}
{{/program:has_sink_functions?}}
import {{program:base_library_package}}.types as _fbthrift_python_types
{{#program:generate_immutable_types}}
import {{program:base_library_package}}.exceptions as _fbthrift_python_exceptions
{{/program:generate_immutable_types}}
{{#program:generate_mutable_types}}
import {{program:base_library_package}}.mutable_types as _fbthrift_python_mutable_types
import {{program:base_library_package}}.mutable_containers as _fbthrift_python_mutable_containers
import {{program:base_library_package}}.mutable_exceptions as _fbthrift_python_mutable_exceptions
import {{program:base_library_package}}.mutable_typeinfos as _fbthrift_python_mutable_typeinfos
{{/program:generate_mutable_types}}

{{#program:include_namespaces}}
{{#has_types?}}

import {{included_module_path}}.{{> types/types_import_path}}
import {{included_module_path}}.{{> types/types_import_path}} as {{included_module_mangle}}__{{> types/types_import_path}}
{{/has_types?}}
{{/program:include_namespaces}}
{{#program:adapter_modules}}
import {{module_path}}
{{/program:adapter_modules}}
{{> types/import_enums}}
{{#program:structs}}


class {{> structs/unadapted_name}}{{!
}}(metaclass={{!
        }}{{#struct:union?}}{{> types/union_metaclass}}{{/struct:union?}}{{!
        }}{{^struct:union?}}{{!
        }}{{#struct:exception?}}{{> types/exception_metaclass}}{{/struct:exception?}}{{!
        }}{{^struct:exception?}}{{> types/struct_metaclass}}{{/struct:exception?}}{{!
        }}{{/struct:union?}}{{!
        }}):
    {{#program:py3_auto_migrate?}}
    {{#struct:allow_inheritance?}}
    _fbthrift_allow_inheritance_DO_NOT_USE = True
    {{/struct:allow_inheritance?}}
    {{/program:py3_auto_migrate?}}
    {{#struct:disable_field_caching?}}
    _fbthrift_disable_field_cache_DO_NOT_USE = True
    {{/struct:disable_field_caching?}}
    _fbthrift_SPEC = (
        {{#struct:fields_ordered_by_id}}
        _fbthrift_python_types.FieldInfo(
            {{field:id}},  # id
            _fbthrift_python_types.{{field:tablebased_qualifier}}, # qualifier
            "{{field:name}}",  # name
            "{{field:py_name}}",  # python name (from @python.Name annotation)
            {{> fields/typeinfo}},  # typeinfo
            {{#field:user_default_value}}{{#field:type}}{{^type:primitive?}}lambda: {{/type:primitive?}}{{/field:type}}{{> types/constant_value }}{{/field:user_default_value}}{{!
            }}{{^field:user_default_value}}None{{/field:user_default_value}},  # default value
            {{> fields/adapter_info }},  # adapter info
            {{> fields/is_primitive }}, # field type is primitive
            {{field:idl_type}}, # IDL type (see BaseTypeEnum)
        ),
        {{/struct:fields_ordered_by_id}}
    ){{!
    }}{{#program:enable_abstract_types?}}{{!
    }}{{^struct:plain?}}{{!
    }}

    _fbthrift_abstract_base_class = _fbthrift_abstract_types.{{struct:py_name}}
    {{!
    }}{{/struct:plain?}}{{!
    }}{{/program:enable_abstract_types?}}


    @staticmethod
    def __get_thrift_name__() -> str:
        return "{{program:name}}.{{> structs/unadapted_name}}"

    @staticmethod
    def __get_thrift_uri__():
        return {{#struct:uri}}"{{struct:uri}}"{{/struct:uri}}{{!
            }}{{^struct:uri}}None{{/struct:uri}}

{{#program:generate_immutable_types}}
    @classmethod
    def _fbthrift_auto_migrate_enabled(cls):
        return {{#program:py3_auto_migrate?}}True{{/program:py3_auto_migrate?}}{{^program:py3_auto_migrate?}}False{{/program:py3_auto_migrate?}}

    @staticmethod
    def __get_metadata__():
        return _fbthrift_metadata__{{#struct:exception?}}exception{{/struct:exception?}}{{^struct:exception?}}struct{{/struct:exception?}}_{{> structs/unadapted_name}}()
    {{!
      makes reflection work in auto-migrated thrift-py3
    }}{{#program:py3_auto_migrate?}}

    @staticmethod
    def __get_reflection__():
        import importlib
        types_reflection = importlib.import_module("{{program:module_path}}.types_reflection")
        return types_reflection.get_reflection__{{struct:py_name}}()
    {{/program:py3_auto_migrate?}}
{{/program:generate_immutable_types}}
{{#program:generate_mutable_types}}
    @staticmethod
    def __get_metadata__():
        raise NotImplementedError(f"__get_metadata__() is not yet implemented for mutable thrift-python structs: {type(self)}")
{{/program:generate_mutable_types}}

    {{#struct:exception?}}
    {{#struct:exception_message?}}

    def __str__(self):
        field = self.{{struct:exception_message}}
        if field is None:
            {{! optional field, stringify }}
            return str(field)
        return field

    {{/struct:exception_message?}}
    {{/struct:exception?}}
    {{#struct:legacy_api?}}
{{#program:generate_mutable_types}}

    def _to_python(self):
        from thrift.python import converter
        import importlib
        immutable_types = importlib.import_module("{{program:module_path}}.thrift_types")
        return converter.to_python_struct(immutable_types.{{> structs/unadapted_name}}, self)

    def _to_mutable_python(self):
        return self
{{/program:generate_mutable_types}}
{{#program:generate_immutable_types}}
    def _to_python(self):
        return self

    def _to_mutable_python(self):
        from thrift.python import mutable_converter
        import importlib
        mutable_types = importlib.import_module("{{program:module_path}}.thrift_mutable_types")
        return mutable_converter.to_mutable_python_struct_or_union(mutable_types.{{> structs/unadapted_name}}, self)
{{/program:generate_immutable_types}}

    def _to_py3(self):
    {{^program:py3_auto_migrate?}}
        import importlib
        py3_types = importlib.import_module("{{program:module_path}}.types")
        from thrift.py3 import converter
        return converter.to_py3_struct(py3_types.{{> structs/unadapted_name}}, self)
    {{/program:py3_auto_migrate?}}
    {{#program:py3_auto_migrate?}}
        return self
    {{/program:py3_auto_migrate?}}

    def _to_py_deprecated(self):
        import importlib
        from thrift.util import converter
        try:
            py_deprecated_types = importlib.import_module("{{program:py_deprecated_module_path}}.ttypes")
            return converter.to_py_struct(py_deprecated_types.{{> structs/unadapted_name}}, self)
        except ModuleNotFoundError:
            py_asyncio_types = importlib.import_module("{{program:py_asyncio_module_path}}.ttypes")
            return converter.to_py_struct(py_asyncio_types.{{> structs/unadapted_name}}, self)
    {{/struct:legacy_api?}}
{{#program:enable_abstract_types?}}{{!
TODO(T208096866)
If the class uses the abstract class as a direct baseclass, it results in the error below.
       TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict)
       subclass of the metaclasses of all its bases

Until we resolve the above error, register the class as virtual subclass of the abstract class.
To workaround the problem that a thrift field named register will cause register to become a property
on the abstract type and prevent the ability to use it to register a virtual subclass,
use abc.ABCMeta.register(cls, subclass) to register.
}}{{^struct:exception?}}

_fbthrift_ABCMeta.register(_fbthrift_abstract_types.{{> structs/unadapted_name}}, {{> structs/unadapted_name}})
{{/struct:exception?}}
{{/program:enable_abstract_types?}}
{{#struct:has_adapter?}}


{{struct:py_name}} = {{adapter:type_hint}}{{#adapter:is_generic?}}[{{> structs/unadapted_name}}]{{/adapter:is_generic?}}
{{/struct:has_adapter?}}
{{> private/alias_prefix}}{{struct:py_name}} = {{struct:py_name}}{{!
}}{{/program:structs}}

{{#program:generate_immutable_types}}
# This unfortunately has to be down here to prevent circular imports
import {{program:module_path}}.thrift_metadata as {{program:module_mangle}}__thrift_metadata
{{/program:generate_immutable_types}}

{{!
    The symbol below is only required for AnyRegistry.register_module.
    Currently, calls to that method only pass thrift_types.
    register_module in its current form expects _fbthrift_all_enums
    to be defined in thrift_types. For now define
    _fbthrift_all_enums here.
}}
_fbthrift_all_enums = [
    {{#program:enums}}
    {{enum:name}},
    {{/program:enums}}
]
{{#program:generate_immutable_types}}{{!
}}{{#program:structs}}


def _fbthrift_metadata__{{#struct:exception?}}exception{{/struct:exception?}}{{^struct:exception?}}struct{{/struct:exception?}}_{{> structs/unadapted_name}}():
    return {{program:module_mangle}}__thrift_metadata.gen_metadata_{{#struct:exception?}}exception{{/struct:exception?}}{{^struct:exception?}}struct{{/struct:exception?}}_{{> structs/unadapted_name}}()
{{/program:structs}}{{!
}}{{/program:generate_immutable_types}}


_fbthrift_all_structs = [
    {{#program:structs}}
    {{> structs/unadapted_name}},
    {{/program:structs}}
]
{{#program:structs?}}
{{#program:generate_mutable_types}}
_fbthrift_python_mutable_types.fill_specs(*_fbthrift_all_structs)
{{/program:generate_mutable_types}}
{{#program:generate_immutable_types}}
_fbthrift_python_types.fill_specs(*_fbthrift_all_structs)
{{/program:generate_immutable_types}}
{{/program:structs?}}
{{> common/constants }}
{{> common/typedef }}
{{#program:services?}}
{{#program:services}}

{{> types/service_arg_types }}

{{#service:interactions}}

{{> types/service_arg_types }}

{{/service:interactions}}
{{/program:services}}


{{#program:generate_mutable_types}}
_fbthrift_python_mutable_types.fill_specs(
{{/program:generate_mutable_types}}
{{#program:generate_immutable_types}}
_fbthrift_python_types.fill_specs(
{{/program:generate_immutable_types}}
{{#program:services}}
    {{> types/service_arg_type_list}}
{{#service:interactions}}
    {{> types/service_arg_type_list}}
{{/service:interactions}}
{{/program:services}}
)
{{/program:services?}}
